﻿#pragma once
#include<iostream>

using namespace std;

namespace Ehundred
{
	template<class T>
	class smart_ptr
	{

	};

	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr=nullptr)
			:_ptr(ptr)
		{}

		auto_ptr(const auto_ptr& ptr)
		{
			if (ptr != *this)
				swap(*this, ptr);
		}

		auto_ptr& operator=(const auto_ptr& ptr)
		{
			if(ptr!=*this)
				swap(*this, ptr);
			
			return *this;
		}

		~auto_ptr()
		{
			delete _ptr;
		}

		auto_ptr& operator*()
		{
			return *_ptr;
		}

		auto_ptr* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr=nullptr)
			:_ptr(ptr)
		{}

		~unique_ptr()
		{
			delete _ptr;
		}

		unique_ptr& operator*()
		{
			return *_ptr;
		}

		unique_ptr* operator->()
		{
			return _ptr;
		}
	private:
		unique_ptr& operator=(const unique_ptr& ptr) = default;
		unique_ptr(const unique_ptr& ptr) = default;

		T* _ptr;
	};


	template<class T>
	class share_ptr
	{
	public:
		share_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{
			_count = new int(1);
		}

		share_ptr(const share_ptr& ptr)
		{
			_ptr = ptr._ptr;
			_count = ptr._count;

			++(*_count);
		}

		share_ptr& operator=(const share_ptr& ptr)
		{
			if (_ptr != ptr._ptr)
			{
				delete_ptr();

				_ptr = ptr._ptr;
				_count=ptr._count;

				++(*_count);
			}

			return *this;
		}

		~share_ptr()
		{
			delete_ptr();
		}

		share_ptr& operator*()
		{
			return *_ptr;
		}

		share_ptr* operator->()
		{
			return _ptr;
		}
	private:
		void delete_ptr()
		{
			--(*_count);

			if (*_count == 0)
			{
				delete _ptr;
				delete _count;
				std::cout << "delete" << std::endl;
			}
		}

		T* _ptr;
		int* _count;
	};
}